package net.ybrj.springKtor.starter.configuration

import io.ktor.application.Application
import io.ktor.routing.routing
import io.ktor.server.engine.ApplicationEngine
import io.ktor.server.engine.ApplicationEngineFactory
import io.ktor.server.engine.embeddedServer
import io.ktor.server.netty.Netty
import net.ybrj.springKtor.core.KtorModule
import net.ybrj.springKtor.core.KtorRouter
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean
import org.springframework.boot.context.properties.ConfigurationProperties
import org.springframework.boot.context.properties.EnableConfigurationProperties
import org.springframework.context.ApplicationContext
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import javax.annotation.Resource

/**
 * spring ktor 配置
 * created by zpf on 2018-12-02
 */
@Configuration
@EnableConfigurationProperties(KtorProperties::class)
open class KtorConfiguration {

    @Resource
    private lateinit var properties: KtorProperties

    /**
     * 注册ktor引擎工厂
     */
    @Bean
    @ConditionalOnMissingBean
    open fun engineFactory(): ApplicationEngineFactory<ApplicationEngine, out ApplicationEngine.Configuration> {
        return Netty
    }

    /**
     * 注册引擎
     * @param engineFactory 依赖引擎工厂
     */
    @Bean
    @ConditionalOnMissingBean
    open fun applicationEngine(engineFactory: ApplicationEngineFactory<ApplicationEngine, out ApplicationEngine.Configuration>, context: ApplicationContext): ApplicationEngine {
        return embeddedServer(engineFactory, host = properties.host, port = properties.port) {
            val modules = context.getBeansOfType(KtorModule::class.java).values
            val routes = context.getBeansOfType(KtorRouter::class.java).values

            //注册模块
            modules.forEach {
                it.apply { register() }
            }

            //注册路由
            routing {
                routes.forEach {
                    it.apply { route() }
                }
            }
        }.start()
    }

    /**
     * 注册应用
     * @param applicationEngine 依赖引擎
     * @param context            依赖spring容器
     */
    @Bean
    @ConditionalOnMissingBean
    open fun application(applicationEngine: ApplicationEngine, context: ApplicationContext): Application {
        return applicationEngine.environment.application
    }
}

/**
 * ktor配置项
 * @param host 服务器主机名
 * @param port 绑定端口
 */
@ConfigurationProperties(prefix = "spring.ktor")
open class KtorProperties(
        open var host: String = "0.0.0.0",
        open var port: Int = 8080
)